﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.SessionState;
using Pixysoft.Framework.Security;
using Pixysoft.Framework.Verifications;
using Pixysoft.Web;
using Pixysoft.Framework.Comet.Core;

namespace Pixysoft.Framework.Comet
{
    class CometAsyncHandler : IHttpAsyncHandler, IReadOnlySessionState
    {
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            string senderCode = StringHelper.GetSenderCode(context);

            if (!Verification.Verifies(senderCode).IsNotNullOrEmpty().Result())
            {
                LoggerHelper.Error("missing my name in request.");

                ICometMessage response = CometManager.CreateMessage("unknown", "unknown");

                CometManager.CometMessageHelper.SetText(response,
                    string.Format("get comet message error, missing myname:{0}.", senderCode));

                CometManager.CometMessageHelper.DoResponse(context.Response, response);

                return CreateInstantResult(context, cb, extraData);
            }

            //判断是否已经有链接，如果有，则当前链接无效

            //2011-01-23 如果已经存在链接，则对方直接失效

            ICometRequest oldRequest = CometRequestPool.Instance.GetRequest(senderCode);

            if (oldRequest != null && oldRequest.IsSubscribed)
            {
                ICometMessage response = CometManager.CreateMessage("unknown", "unknown");

                CometManager.CometMessageHelper.SetText(response,
                    string.Format("same connection exist, current connection invalid."));

                response.TimeStamp = StringHelper.GetTimestamp();

                oldRequest.AddMessages(response);

                LoggerHelper.Info("{0}:same request existed, add response and remove. sender:{1}, message.count:{2}",
                    oldRequest.RequestUid, oldRequest.SenderCode, oldRequest.MessageCount);

                CometRequestPool.Instance.RemoveRequest(oldRequest);

                //CometManager.CometMessageHelper.DoResponse(context.Response, response);

                //return CreateInstantResult(context, cb, extraData);
            }

            CometAsyncResult result = new CometAsyncResult(context, cb, extraData);
            Pixysoft.MultiThread.AsyncInvoker<string>.Invoke(result.BeginWaitRequest, senderCode);
            return result;
        }

        private IAsyncResult CreateInstantResult(HttpContext context, AsyncCallback cb, object extraData)
        {
            CometInstantResult result = new CometInstantResult(context, cb, extraData);
            result.SetCompleted();
            return result;
        }

        public void EndProcessRequest(IAsyncResult result)
        {
            CometAsyncResult cometAsyncResult = result as CometAsyncResult;

            if (cometAsyncResult == null)
                return;

            ICometMessage message = null;

            if (cometAsyncResult.ResponseMessage != null)
            {
                message = cometAsyncResult.ResponseMessage;
            }
            else
            {
                message = CometManager.CreateMessage("unknown", "unknown");

                message.Content = new byte[] { };
            }

            CometManager.CometMessageHelper.DoResponse(cometAsyncResult.HttpContext.Response, message);
        }



        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }

    class CometInstantResult : IAsyncResult
    {
        private bool isCompleted = false;
        private AsyncCallback callback;
        private object asyncState;
        private HttpContext context = null;

        public CometInstantResult(HttpContext context, AsyncCallback callback, object asyncState)
        {
            this.callback = callback;
            this.context = context;
            this.asyncState = asyncState;
        }

        internal void SetCompleted()
        {
            this.isCompleted = true;

            if (callback != null)
                callback(this);
        }


        public object AsyncState
        {
            get { return this.asyncState; }
        }

        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get { throw new InvalidOperationException("ASP.NET Should never use this property"); }
        }

        public bool CompletedSynchronously
        {
            get { return false; }
        }

        public bool IsCompleted
        {
            get { return this.isCompleted; }
        }
    }

    class CometAsyncResult : IAsyncResult
    {
        private bool isCompleted = false;
        private AsyncCallback callback = null;
        private object asyncState = null;
        private HttpContext context = null;
        private ICometMessage responseMessage = null;

        public CometAsyncResult(HttpContext context, AsyncCallback callback, object asyncState)
        {
            this.callback = callback;
            this.context = context;
            this.asyncState = asyncState;
        }

        internal HttpContext HttpContext
        {
            get { return this.context; }
        }

        internal ICometMessage ResponseMessage
        {
            get
            {
                return responseMessage;
            }
        }

        internal void SetCompleted()
        {
            this.isCompleted = true;

            if (callback != null)
                callback(this);
        }

        internal void BeginWaitRequest(string myName)
        {
            ICometMessage message = null;

            try
            {
                message = CometManager.CreateWebRemoting().GetCometMessage(myName, myName);
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);

                message = CometManager.CreateMessage("unknown", "unknown");

                CometManager.CometMessageHelper.SetText(message,
                    string.Format("get response error. {0}", ex.Message));
            }

            if (message == null)
            {
                message = CometManager.CreateMessage("unknown", "unknown");

                message.Content = new byte[] { };
            }

            this.responseMessage = message;

            this.SetCompleted();
        }



        public object AsyncState
        {
            get { return this.asyncState; }
        }

        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get { throw new InvalidOperationException("ASP.NET Should never use this property"); }
        }

        public bool CompletedSynchronously
        {
            get { return false; }
        }

        public bool IsCompleted
        {
            get { return this.isCompleted; }
        }

    }
}
